package com.mcxx.modules.miniSalvation.fundpay.service.write;

import cn.hutool.core.util.ArrayUtil;
import com.google.common.collect.Lists;
import com.mcxx.common.exception.BizException;
import com.mcxx.modules.base.utils.FundPayBizDealUtils;
import com.mcxx.modules.miniSalvation.fundpay.dao.read.FundPayFamilyReadDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.read.FundPayMemberReadDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayFamilyWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayMemberWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dto.*;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayFamilyEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayMemberEntity;
import com.mcxx.modules.miniSalvation.fundpay.param.FundPayParam;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayFamilyReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayMemberReadService;
import com.mcxx.util.Constant;
import com.mcxx.util.FailureCode;
import com.yinhai.ta404.core.transaction.annotation.TaTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
@TaTransactional
public class FundPayFamilyWriteService {
    private static final Logger logger = LoggerFactory.getLogger(FundPayFamilyWriteService.class);
    @Autowired
    private FundPayFamilyWriteDao fundPayFamilyWriteDao;
    @Autowired
    private FundPayFamilyReadService fundPayFamilyReadService;
    @Autowired
    private FundPayMemberReadService fundPayMemberReadService;
    @Autowired
    private FundPayMemberWriteService fundPayMemberWriteService;


    public int deleteByFundPayIds(List<String> fundPayIdList){
        return fundPayFamilyWriteDao.deleteByFundPayIds(fundPayIdList);
    }


    public void updateIgnoreNull(FundPayFamilyEntity fundPayFamilyEntity){
        int rst = fundPayFamilyWriteDao.updateIgnoreNull(fundPayFamilyEntity);
        if(rst <= 0){
            throw new BizException("-1", "修改名册家庭信息异常");
        }
    }


    public int insertFamilyMember(List<FundPayFamilyEntity> fundPayFamilyList,  List<FundPayMemberEntity> fundPayMemberList){
        if(null==fundPayFamilyList || fundPayFamilyList.size()==0) {
            return 0;
        }
        String fundpayId = fundPayFamilyList.get(0).getFundPayId();
        logger.info("发放名册fundpayid={}，家庭名册记录数：{}， 成员名册数据：{}", fundpayId, fundPayFamilyList.size(), fundPayMemberList.size());
        int rst = 0;
        List<List<FundPayFamilyEntity>> groupFundPayFamilyEntityList = Lists.partition(fundPayFamilyList, 500);
        for (List<FundPayFamilyEntity> familyEntity: groupFundPayFamilyEntityList) {

            rst = fundPayFamilyWriteDao.inserts(familyEntity);
            if(rst <= 0){
                logger.error("资金发放名册家庭insert失败");
                throw new BizException("资金发放名册家庭insert失败");
            }
        }


        List<List<FundPayMemberEntity>> groupFundPayMemberEntityList = Lists.partition(fundPayMemberList, 500);
        for(List<FundPayMemberEntity> memberEntityList : groupFundPayMemberEntityList){
            rst = fundPayMemberWriteService.inserts(memberEntityList);
            if(rst <= 0){
                logger.error("资金发放名册成员insert失败");
                throw new BizException("资金发放名册成员insert失败");
            }
        }
        return  rst;
    }


    public void deleteByFundPayIdAndFamilyId(String fundPayId, List<String> familyIdList){
        if(familyIdList.size() <= 0){
            return;
        }
        int rst = fundPayFamilyWriteDao.deleteByFundPayIdAndFamilyId(fundPayId, familyIdList);
        if(rst <= 0){
            throw new BizException("-1", "移除家庭失败");
        }
    }





    public void saveCapitalFamilyByOrderId(List<String> orderIdList, CapitalFundPayDTO capitalFundPayDTO){
        if(orderIdList.size() <= 0){
            return;
        }

        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getSaveCapitalFamilyByOrderId(orderIdList, capitalFundPayDTO.getCostType(), capitalFundPayDTO.getBusinessType());


        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getCapitalMemberList(fundPayFamilyList, capitalFundPayDTO);


        this.perfectFundPayInfo(fundPayFamilyList, fundPayMemberList, capitalFundPayDTO.getId(), capitalFundPayDTO.getPayDate(), capitalFundPayDTO.getCostType());


        this.insertFamilyMember(fundPayFamilyList, fundPayMemberList);
    }


    public void perfectFundPayInfo( List<FundPayFamilyEntity> fundPayFamilyList,
                                     List<FundPayMemberEntity> fundPayMemberList,
                                    String fundPayId,
                                    Date payDate,
                                    String costType){
        Date createDate = new Date();
        Map<String, String> familyFundPayFamilyIdMap = new HashMap<>();

        for (FundPayFamilyEntity fundPayFamilyEntity : fundPayFamilyList) {

            fundPayFamilyEntity.setId(Constant.getUUID());

            fundPayFamilyEntity.setFundPayId(fundPayId);

            fundPayFamilyEntity.setPayDate(payDate);
            fundPayFamilyEntity.setFundNumber(fundPayFamilyEntity.getFundNumber());

            fundPayFamilyEntity.setCostType(costType);

            fundPayFamilyEntity.setCreateTime(createDate);

            familyFundPayFamilyIdMap.put(fundPayFamilyEntity.getFamilyId(), fundPayFamilyEntity.getId());
        }

        for (FundPayMemberEntity fundMemberEntity : fundPayMemberList) {

            fundMemberEntity.setId(Constant.getUUID());

            fundMemberEntity.setFundPayId(fundPayId);
            fundMemberEntity.setFundNumber(fundMemberEntity.getFundNumber());

            fundMemberEntity.setPayDate(payDate);

            fundMemberEntity.setCostType(costType);

            fundMemberEntity.setCreateTime(createDate);

            fundMemberEntity.setFundPayFamilyId(familyFundPayFamilyIdMap.get(fundMemberEntity.getFamilyId()));
        }
    }









    public void saveStandFamilyByOrderId(List<String> orderIdList, StandFundPayDTO standFundPayDTO){
        if(orderIdList.size() <= 0){
            return;
        }

        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getSaveStandFamilyByOrderId(orderIdList, standFundPayDTO.getCostType(), standFundPayDTO.getBusinessType());


        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getMemberForStand(fundPayFamilyList, standFundPayDTO);


        this.perfectFundPayInfo(fundPayFamilyList, fundPayMemberList, standFundPayDTO.getId(), standFundPayDTO.getPayDate(), standFundPayDTO.getCostType());


        this.insertFamilyMember(fundPayFamilyList, fundPayMemberList);
    }








    public int deleteFamilyByDelMember(String fundPayId, List<String> memberIdList){
        return fundPayFamilyWriteDao.deleteFamilyByDelMember(fundPayId, memberIdList);
    }



    public int updateFamilyNumAndFundNumber(String fundPayId, List<String> familyIdList){
        return fundPayFamilyWriteDao.updateFamilyNumAndFundNumber(fundPayId,familyIdList);
    }


    public void calcGrantStandardByMember( List<FundPayFamilyEntity> fundPayFamilyList,
                                           List<FundPayMemberEntity> fundPayMemberList, AllowanceFundPayDTO allowanceFundPayDTO){
        Map<String, String> fundPayFamilyIdMap = new HashMap<>();
        Date createDate = new Date();

        for (FundPayFamilyEntity fundPayFamilyEntity : fundPayFamilyList) {

            fundPayFamilyEntity.setId(Constant.getUUID());

            fundPayFamilyEntity.setFundPayId(allowanceFundPayDTO.getId());

            fundPayFamilyEntity.setPayDate(allowanceFundPayDTO.getPayDate());

            fundPayFamilyEntity.setCreateTime(createDate);

            fundPayFamilyIdMap.put(fundPayFamilyEntity.getFamilyId(), fundPayFamilyEntity.getId());
        }

        Map<String, Integer> familyMemberNumMap = new HashMap<>();
        for (FundPayMemberEntity fundMemberEntity : fundPayMemberList) {
            String familyId = fundMemberEntity.getFamilyId();

            fundMemberEntity.setId(Constant.getUUID());

            fundMemberEntity.setFundPayId(allowanceFundPayDTO.getId());

            fundMemberEntity.setPayDate(allowanceFundPayDTO.getPayDate());

            fundMemberEntity.setFundNumber(allowanceFundPayDTO.getGrantStandard());

            fundMemberEntity.setCreateTime(createDate);

            fundMemberEntity.setFundPayFamilyId(fundPayFamilyIdMap.get(familyId));

            familyMemberNumMap.put(familyId,
                    familyMemberNumMap.containsKey(familyId) ? familyMemberNumMap.get(familyId) + 1 : 1);
        }

        for(FundPayFamilyEntity entity: fundPayFamilyList){

            entity.setPersonNumber(familyMemberNumMap.get(entity.getFamilyId()));

            double familyFundNumber = allowanceFundPayDTO.getGrantStandard() * entity.getPersonNumber();
            entity.setFundNumber(familyFundNumber);
        }
    }







    public void updateCustomFamilyNumber(String fundPayId, String fundPayFamilyId){
        int rst = fundPayFamilyWriteDao.updateFamilyNumber(fundPayId, fundPayFamilyId);
        if(rst <= 0){
            throw new BizException("-1","金额修改失败");
        }
    }


    public void updateCustomFamilyNumber(String fundPayFamilyId, double fundNumber){
        FundPayFamilyEntity fundPayFamilyEntity = new FundPayFamilyEntity();
        fundPayFamilyEntity.setId(fundPayFamilyId);
        fundPayFamilyEntity.setFundNumber(fundNumber);
        this.updateIgnoreNull(fundPayFamilyEntity);
    }


    public void updateCustomFamilyRemark(String fundPayFamilyId, String remark){
        FundPayFamilyEntity fundPayFamilyEntity = new FundPayFamilyEntity();
        fundPayFamilyEntity.setId(fundPayFamilyId);
        fundPayFamilyEntity.setRemark(remark);
        this.updateIgnoreNull(fundPayFamilyEntity);
    }


    public void calcCustomByMember(List<FundPayFamilyEntity> fundPayFamilyList,
                                   List<FundPayMemberEntity> fundPayMemberList,
                                   CustomFundPayDTO customFundPayDTO,
                                   Map<String, String> familyFundPayFamilyIdMap){
        Date createDate = new Date();

        for (FundPayFamilyEntity fundPayFamilyEntity : fundPayFamilyList) {

            fundPayFamilyEntity.setId(Constant.getUUID());

            fundPayFamilyEntity.setFundPayId(customFundPayDTO.getId());

            fundPayFamilyEntity.setPayDate(customFundPayDTO.getPayDate());

            fundPayFamilyEntity.setCreateTime(createDate);

            fundPayFamilyEntity.setFundNumber(0d);

            familyFundPayFamilyIdMap.put(fundPayFamilyEntity.getFamilyId(), fundPayFamilyEntity.getId());
        }

        Map<String, Integer> familyMemberNumMap = new HashMap<>();
        for (FundPayMemberEntity fundMemberEntity : fundPayMemberList) {
            String familyId = fundMemberEntity.getFamilyId();

            fundMemberEntity.setId(Constant.getUUID());

            fundMemberEntity.setFundPayId(customFundPayDTO.getId());

            fundMemberEntity.setPayDate(customFundPayDTO.getPayDate());

            fundMemberEntity.setFundNumber(0D);

            fundMemberEntity.setCreateTime(createDate);

            fundMemberEntity.setFundPayFamilyId(familyFundPayFamilyIdMap.get(familyId));

            familyMemberNumMap.put(familyId,
                    familyMemberNumMap.containsKey(familyId) ? familyMemberNumMap.get(familyId) + 1 : 1);
        }

        for(FundPayFamilyEntity entity: fundPayFamilyList){

            entity.setPersonNumber(familyMemberNumMap.get(entity.getFamilyId()));
        }
    }



    public void calcCustomByMember(List<FundPayFamilyEntity> fundPayFamilyList,
                                   List<FundPayMemberEntity> fundPayMemberList, CustomFundPayDTO customFundPayDTO){
        Map<String, String> fundPayFamilyIdMap = new HashMap<>();
        Date createDate = new Date();

        for (FundPayFamilyEntity fundPayFamilyEntity : fundPayFamilyList) {

            fundPayFamilyEntity.setId(Constant.getUUID());

            fundPayFamilyEntity.setFundPayId(customFundPayDTO.getId());

            fundPayFamilyEntity.setPayDate(customFundPayDTO.getPayDate());

            fundPayFamilyEntity.setCreateTime(createDate);

            fundPayFamilyEntity.setFundNumber(0d);

            fundPayFamilyIdMap.put(fundPayFamilyEntity.getFamilyId(), fundPayFamilyEntity.getId());
        }

        Map<String, Integer> familyMemberNumMap = new HashMap<>();
        for (FundPayMemberEntity fundMemberEntity : fundPayMemberList) {
            String familyId = fundMemberEntity.getFamilyId();

            fundMemberEntity.setId(Constant.getUUID());

            fundMemberEntity.setFundPayId(customFundPayDTO.getId());

            fundMemberEntity.setPayDate(customFundPayDTO.getPayDate());

            fundMemberEntity.setFundNumber(0D);

            fundMemberEntity.setCreateTime(createDate);

            fundMemberEntity.setFundPayFamilyId(fundPayFamilyIdMap.get(familyId));

            familyMemberNumMap.put(familyId,
                    familyMemberNumMap.containsKey(familyId) ? familyMemberNumMap.get(familyId) + 1 : 1);
        }

        for(FundPayFamilyEntity entity: fundPayFamilyList){

            entity.setPersonNumber(familyMemberNumMap.get(entity.getFamilyId()));
        }
    }



    public void addFamilyForCustom(List<String> orderIdList, CustomFundPayDTO customFundPayDTO){
        if(orderIdList.size() <= 0){
            return;
        }

        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getSaveCustomFamilyByOrderId(orderIdList, customFundPayDTO.getBusinessType());


        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getCustomMemberList(fundPayFamilyList);


        this.perfectFundPayInfo(fundPayFamilyList, fundPayMemberList, customFundPayDTO.getId(), customFundPayDTO.getPayDate(), customFundPayDTO.getCostType());


        this.insertFamilyMember(fundPayFamilyList, fundPayMemberList);
    }









    public int insertsExcel(List<FundPayMemberEntity> customFundPayMemberList,
                            Map<String, FundPayMemberEntity> excelMemberMap,
                            String customFundPayId,
                            FundPayEntity fundPayEntity) {
        Date createTime = new Date();

        customFundPayMemberList.forEach(entity->{

            FundPayMemberEntity dto = excelMemberMap.get(entity.getIdcard());

            entity.setCreateTime(createTime);

            entity.setFundNumber(0d);

            entity.setPersonNumber(1);

            entity.setId(Constant.getUUID());

            entity.setFundPayId(customFundPayId);

            entity.setFundNumber(dto.getFundNumber());

            entity.setRemark(dto.getRemark());
            entity.setPayDate(fundPayEntity.getPayDate());
        });

        int rst = fundPayFamilyWriteDao.insertCustomMember(customFundPayMemberList);
        if(rst <= 0){
            throw new BizException("-1", "成员添加失败,数据库操作异常");
        }
        return rst;
    }


    public int updateAddMemberNum(String customFundPayId, int memberNum, int familyNum) {
        int rst = fundPayFamilyWriteDao.updateAddMemberNum(customFundPayId, memberNum, familyNum);
        if(rst <= 0){
            throw new BizException(FailureCode.ERR_10041);
        }
        return rst;
    }

    public int updateCustomRollMembers(List<FundPayMemberEntity> rollMembers) {
        int rst = fundPayFamilyWriteDao.updateCustomRollMembers(rollMembers);
        if(rst <= 0){
            throw new BizException(FailureCode.ERR_10041);
        }
        return rst;
    }

    public int updateCustomRollFamily(List<FundPayFamilyDTO> rollFamily) {
        return fundPayFamilyWriteDao.updateCustomRollFamily(rollFamily);
    }

    public int insertRollFamily(FundPayFamilyDTO familyDTO) {
        int rst = fundPayFamilyWriteDao.insertRollFamily(familyDTO);
        if(rst <= 0){
            throw new BizException(FailureCode.ERR_10041);
        }
        return rst;
    }


    public List<FundPayMemberEntity> partMemberInfo(List<FundPayMemberEntity> customFundPayMemberList,
                               Map<String, FundPayMemberEntity> excelMemberMap,
                               String customFundPayId,
                               FundPayEntity fundPayEntity) {
        Date createTime = new Date();

        customFundPayMemberList.forEach(entity->{

            FundPayMemberEntity dto = excelMemberMap.get(entity.getIdcard());

            entity.setCreateTime(createTime);

            entity.setFundNumber(0d);

            entity.setPersonNumber(1);

            entity.setId(Constant.getUUID());

            entity.setFundPayId(customFundPayId);

            entity.setFundNumber(dto.getFundNumber());

            entity.setRemark(dto.getRemark());
            entity.setPayDate(fundPayEntity.getPayDate());
        });
        return customFundPayMemberList;
    }


    public int insertRollMembers(List<FundPayMemberEntity> memberList) {
        int rst = fundPayFamilyWriteDao.insertCustomMember(memberList);
        if(rst <= 0){
            throw new BizException("-1", "成员添加失败,数据库操作异常");
        }
        return rst;
    }


    public void updateFundsFamily(String familyId, String changeData) {
        FundPayFamilyEntity obj = new FundPayFamilyEntity();
        obj.setId(familyId);
        BigDecimal fundNumber = new BigDecimal(changeData);
        obj.setFundNumber(fundNumber.doubleValue());
        fundPayFamilyWriteDao.updateIgnoreNull(obj);
    }


    public void saveDisperseStandFamilyByOrderId(List<String> orderIdList, StandFundPayDTO standFundPayDTO) {
        if (orderIdList.isEmpty()) {
            return;
        }

        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getSaveStandFamilyByOrderId(orderIdList, standFundPayDTO.getCostType(), standFundPayDTO.getBusinessType());


        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getMemberForStand(fundPayFamilyList, standFundPayDTO);


        List<String> familyIds = fundPayMemberList.stream().map(FundPayMemberEntity::getFamilyId).collect(Collectors.toList());

        fundPayFamilyWriteDao.deleteByFundPayIdAndFamilyId(standFundPayDTO.getId(), familyIds);
        List<FundPayMemberEntity> rollMembers = fundPayMemberReadService.getMemberFromFundPay(familyIds,standFundPayDTO);
        rollMembers.addAll(fundPayMemberList);

        List<FundPayFamilyEntity> lastFamily = FundPayBizDealUtils.generatorFamilyByMemberInfo(rollMembers,standFundPayDTO,fundPayFamilyList);


        this.perfectFundPayInfo(lastFamily, fundPayMemberList, standFundPayDTO.getId(), standFundPayDTO.getPayDate(), standFundPayDTO.getCostType());


        this.insertFamilyMember(lastFamily, fundPayMemberList);
    }
}
